/* Copyright (c) 2025，Shandong University — School of Cyber Science and Technology
* Contributor: ShaoYan Zhang, XiaoKai Gong, YiMing Zhou, HeYang Ding
 * Instructor:  Weijia Wang
*/
/*
 * This file is part of the openHiTLS project.
 *
 * openHiTLS is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

/* BEGIN_HEADER */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "app_speed.h"
#include "app_errno.h"
#include "app_help.h"
#include "app_print.h"
#include "app_opt.h"
#include "app_provider.h"
#include "bsl_uio.h"
#include "crypt_eal_cipher.h"
#include "crypt_eal_mac.h"
#include "bsl_errno.h"

/* INCLUDE_SOURCE
 * ${HITLS_ROOT_PATH}/apps/src/app_speed.c
 * ${HITLS_ROOT_PATH}/apps/src/app_opt.c
 * ${HITLS_ROOT_PATH}/apps/src/app_utils.c
 */
/* END_HEADER */

typedef struct {
    uint16_t version;
} ResumeTestInfo;

typedef struct {
    int argc;
    char **argv;
    int expect;
} OptTestData;

static int32_t AppInit(void)
{
    int32_t ret = AppPrintErrorUioInit(stderr);
    if (ret != HITLS_APP_SUCCESS) {
        return ret;
    }
    if (APP_Create_LibCtx() == NULL) {
        (void)AppPrintError("Create g_libCtx failed\n");
        return HITLS_APP_INVALID_ARG;
    }
    return HITLS_APP_SUCCESS;
}

static void AppUninit(void)
{
    AppPrintErrorUioUnInit();
    HITLS_APP_FreeLibCtx();
}

/**
 * @test UT_HITLS_APP_SPEED_TC001
 * @spec  -
 * @title  speed command line specified block size cipher algorithm performance test
 */

/* BEGIN_CASE */
void UT_HITLS_APP_SPEED_TC001(void)
{
    char *argv[][12] = {
        {"speed", "-cipher", "aes-128-cbc", "-enc", "-seconds", "5", "-bytes", "1024", "-threads", "1"},
        {"speed", "-cipher", "aes-192-ctr", "-dec", "-seconds", "3", "-bytes", "256"},
        {"speed", "-cipher", "aes-256-ofb", "-seconds", "3", "-bytes", "1024", "-threads", "3"},
        {"speed", "-cipher", "sm4-cbc", "-enc", "-bytes", "1024", "-threads", "5"},
        {"speed", "-cipher", "sm4-gcm", "-dec", "-seconds", "3", "-bytes", "2048", "-threads", "2"},
    };

    OptTestData testData[] = {
        {10, argv[0], HITLS_APP_SUCCESS},
        {8, argv[1], HITLS_APP_SUCCESS},
        {9, argv[2], HITLS_APP_SUCCESS},
        {8, argv[3], HITLS_APP_SUCCESS},
        {10, argv[4], HITLS_APP_SUCCESS},
    };

    ASSERT_EQ(AppInit(), HITLS_APP_SUCCESS);
    for (int i = 0; i < (int)(sizeof(testData) / sizeof(OptTestData)); ++i) {
        int ret = HITLS_SpeedMain(testData[i].argc, testData[i].argv);
        ASSERT_EQ(ret, testData[i].expect);
    }
    
EXIT:
    AppUninit();
    return;
}
/* END_CASE */

/**
 * @test UT_HITLS_APP_SPEED_TC002
 * @spec  -
 * @title  speed command line specified block size MAC algorithm performance test
 */

/* BEGIN_CASE */
void UT_HITLS_APP_SPEED_TC002(void)
{
    char *argv[][12] = {
        {"speed", "-mac", "md5", "-seconds", "2", "-bytes", "1024", "-threads", "4"},
        {"speed", "-mac", "sha256", "-seconds", "2", "-bytes", "2048", "-threads", "2"},
        {"speed", "-mac", "sm3", "-seconds", "2", "-bytes", "1024", "-threads", "2"},
    };

    OptTestData testData[] = {
        {9, argv[0], HITLS_APP_SUCCESS},
        {9, argv[1], HITLS_APP_SUCCESS},
        {9, argv[2], HITLS_APP_SUCCESS},
    };

    ASSERT_EQ(AppInit(), HITLS_APP_SUCCESS);
    for (int i = 0; i < (int)(sizeof(testData) / sizeof(OptTestData)); ++i) {
        int ret = HITLS_SpeedMain(testData[i].argc, testData[i].argv);
        ASSERT_EQ(ret, testData[i].expect);
    }
    
EXIT:
    AppUninit();
    return;
}
/* END_CASE */

/**
 * @test UT_HITLS_APP_SPEED_TC003
 * @spec  -
 * @title  speed command line cipher algorithm and MAC algorithm automatic performance test
 */

/* BEGIN_CASE */
void UT_HITLS_APP_SPEED_TC003(void)
{
    char *argv[][8] = {
        {"speed", "-cipher", "aes-128-ofb", "-enc", "-seconds", "2", "-auto-block"},
        {"speed", "-cipher", "sm4-ecb", "-dec", "-seconds", "2", "-auto-block"},
        {"speed", "-mac", "md5", "-seconds", "2", "-auto-block"},
        {"speed", "-mac", "sha3-256", "-seconds", "2", "-auto-block"},
    };

    OptTestData testData[] = {
        {7, argv[0], HITLS_APP_SUCCESS},
        {7, argv[1], HITLS_APP_SUCCESS},
        {6, argv[2], HITLS_APP_SUCCESS},
        {6, argv[3], HITLS_APP_SUCCESS},
    };

    ASSERT_EQ(AppInit(), HITLS_APP_SUCCESS);
    for (int i = 0; i < (int)(sizeof(testData) / sizeof(OptTestData)); ++i) {
        int ret = HITLS_SpeedMain(testData[i].argc, testData[i].argv);
        ASSERT_EQ(ret, testData[i].expect);
    }
    
EXIT:
    AppUninit();
    return;
}
/* END_CASE */

/**
 * @test UT_HITLS_APP_SPEED_TC004
 * @spec -
 * @title Command Line Input Abnormal Test
 *  1. Invalid cipher algorithm name
 *  2. Invalid MAC name
 *  3. No algorithm specified
 *  4. Unsupported block size for cipher algorithm
 *  5. Invalid block size (negative number)
 *  6. Extra, unrecognizable command line parameters
 */

/* BEGIN_CASE */
void UT_HITLS_APP_SPEED_TC004(void)
{
    char *argv[][10] = {
        {"speed", "-cipher", "invalid-alg", "-enc", "-seconds", "1", "-bytes", "1024"},
        {"speed", "-mac", "invalid-mac", "-seconds", "1", "-bytes", "1024"},
        {"speed", "-seconds", "1", "-bytes", "1024"},
        {"speed", "-cipher", "aes-128-cbc", "-enc", "-seconds", "1", "-bytes", "100"},
        {"speed", "-cipher", "aes-128-cbc", "-enc", "-seconds", "1", "-bytes", "-1024"},
        {"speed", "-cipher", "aes-128-cbc", "-enc", "-seconds", "1", "-bytes", "1024", "-unknown-option"},
    };

    OptTestData testData[] = {
        {8,  argv[0], HITLS_APP_OPT_VALUE_INVALID},
        {7,  argv[1], HITLS_APP_OPT_VALUE_INVALID},
        {5,  argv[2], HITLS_APP_OPT_VALUE_INVALID},
        {8,  argv[3], HITLS_APP_OPT_VALUE_INVALID},
        {8,  argv[4], HITLS_APP_OPT_UNKOWN},
        {9, argv[5], HITLS_APP_OPT_UNKOWN},
    };

    ASSERT_EQ(AppInit(), HITLS_APP_SUCCESS);
    for (int i = 0; i < (int)(sizeof(testData) / sizeof(OptTestData)); ++i) {
        int ret = HITLS_SpeedMain(testData[i].argc, testData[i].argv);
        ASSERT_EQ(ret, testData[i].expect);
    }
    
EXIT:
    AppUninit();
    return;
}
/* END_CASE */
